#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

struct msgbuf
{
    long mtype;
    char buf[32];
};

//定义Jack和Rose的类型
#define JACKTYPE 1;
#define ROSETYPE 2;

//生成key值
key_t KeyCreate()
{
    key_t key=ftok("./app",'a');
    if (-1==key)
    {
        perror("ftok err\n");
        return -1;
    }
    return key;
}

//生成消息队列的msgid
int MsgidCreate(key_t key)
{
    int msgid=msgget(key,IPC_CREAT|IPC_EXCL|0666);
    if(-1==msgid)
    {
        if(EEXIST==errno)
        {
            msgid=msgget(key,0666);
        }
        else
        {
            perror("msgget err\n");
            return -1;
        }
    }
    return msgid;
}

//Jack的输入函数，用于向Rose输入数据
void JackInputData(struct msgbuf msg,int msgid,int size)
{
    msg.mtype=JACKTYPE;
    while (1)
    {
        printf("请输入数据(输入quit退出):\n");
        scanf("%s",msg.buf);//输入数据
        msgsnd(msgid,&msg,size,0);
        if (strcmp("quit",msg.buf)==0)//quit则向Jack和Rose的父进程发送quit信息
        {
            msg.mtype=ROSETYPE;
            msgsnd(msgid,&msg,size,0);
            break;
        }
    }
}

//Jack的接收函数，用于接收Rose的数据
void JackReceiveData(struct msgbuf m,int msgid,int size,pid_t pid)
{
    while (1)
    {
        msgrcv(msgid,&m,size,2,0);//接收数据
        printf("接收到的数据为:%s\n",m.buf);
        if (strcmp("quit",m.buf)==0)//quit则杀死子进程，之后退出
        {
            kill(pid,SIGKILL);
            break;
        }
    }
}

//Jack的输入和输出函数，使用父子进程处理Jack的操作,父进程接收，子进程输入
int Jack_Input_and_Output(struct msgbuf msg,int msgid,pid_t pid)
{
    struct msgbuf m;//用于接收的结构体
    int size=sizeof(struct msgbuf)-sizeof(long);
    pid=fork();
    if (pid<0)//错误
    {
        perror("fork err\n");
        msgctl(msgid,IPC_RMID,NULL);
        return -1;
    }
    else if(pid==0)//子进程，输入
    {
        JackInputData(msg,msgid,size);
        exit(0);
    }
    else//父进程，接收
    {
        JackReceiveData(m,msgid,size,pid);
        msgctl(msgid,IPC_RMID,NULL);
        wait(NULL);
    }
    return 0;
}

int main(int argc,char const* argv[])
{
    pid_t pid=-1;
    struct msgbuf msg;

    key_t key=KeyCreate();
    int msgid=MsgidCreate(key);

    Jack_Input_and_Output(msg,msgid,pid);

    msgctl(msgid,IPC_RMID,NULL);

    return 0;
}